////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// <copyright>Copyright 2008-2011 Andreas Huber Doenni</copyright>
// Distributed under the GNU General Public License version 2 (GPLv2).
// See accompanying file License.txt or copy at http://phuse.codeplex.com/license.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

namespace Phuse
{
    using System;
    using System.Diagnostics.CodeAnalysis;

    /// <summary>Defines the methods implemented by all visitable types.</summary>
    /// <typeparam name="TBase">The visitable base type.</typeparam>
    /// <remarks>
    /// <para>Clients must derive their own type from this interface. The types implementing that client
    /// interface must also implement <see cref="IVisitable{T, U}"/>.</para>
    /// <para>This interface is a part of an implementation of the
    /// <a href="http://www.objectmentor.com/resources/articles/acv.pdf">acyclic visitor pattern</a>.</para>
    /// </remarks>
    /// <threadsafety static="true" instance="false"/>
    public interface IVisitable<TBase> where TBase : IVisitable<TBase>
    {
        /// <summary>Lets <paramref name="visitor"/> visit this object.</summary>
        /// <param name="visitor">The visitor visiting this object.</param>
        /// <exception cref="ArgumentNullException"><paramref name="visitor"/> equals <c>null</c>.</exception>
        /// <exception cref="InvalidCastException"><c>this</c> cannot be downcast to the derived type. This can
        /// only happen when a type implementing <see cref="IVisitable{T, U}"/> does not pass its own or a derived type
        /// for the first parameter.</exception>
        /// <remarks>If <paramref name="visitor"/> can be cast to <see cref="IVisitor{T, U}"/>, with TDerived
        /// being the the type implementing this interface or any of its subtypes, then
        /// ((<see cref="IVisitor{T, U}">IVisitable&lt;TDerived, TBase&gt;</see>)
        /// <paramref name="visitor"/>).<see cref="IVisitor{T, U}.OnVisit">OnVisit</see>((TDerived) this) is
        /// called; otherwise <paramref name="visitor"/>.<see cref="IVisitor{T}.OnVisit">OnVisit</see>((TBase) this) is
        /// called.</remarks>
        void Accept(IVisitor<TBase> visitor);
    }

    /// <summary>Defines the methods implemented by a visitable object of type <typeparamref name="TDerived"/>.
    /// </summary>
    /// <typeparam name="TDerived">The type implementing this interface or any of its subtypes, usually the most-derived
    /// type.</typeparam>
    /// <typeparam name="TBase">The visitable base type.</typeparam>
    /// <remarks>
    /// <para>Client types usually implement this interface simply by deriving from <see cref="Visitable{T, U}"/>. Only
    /// if this is not possible (e.g. when the client type needs to derive from another base class) then this interface
    /// must be implemented manually using <see cref="VisitableHelper"/>.</para>
    /// <para>This interface is a part of an implementation of the
    /// <a href="http://www.objectmentor.com/resources/articles/acv.pdf">acyclic visitor pattern</a>.</para>
    /// </remarks>
    /// <threadsafety static="true" instance="false"/>
    [SuppressMessage("Microsoft.Design", "CA1040:AvoidEmptyInterfaces", Justification = "Not an empty interface, CA bug?")]
    public interface IVisitable<TDerived, TBase> : IVisitable<TBase>
        where TDerived : IVisitable<TDerived, TBase>
        where TBase : IVisitable<TBase>
    {
    }
}
